package com.tmrnavi.sensordaq;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.location.OnNmeaMessageListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
import java.util.Timer;
import java.util.TimerTask;

public class MainActivity extends AppCompatActivity {

    TextView tv_time, tv_wx, tv_wy, tv_wz, tv_fx, tv_fy, tv_fz, tv_mx, tv_my, tv_mz, tv_pr;     // 传感器数据显示控件
    TextView tv_gnss_tim, tv_gnss_lat, tv_gnss_lng, tv_gnss_alt, tv_gnss_yaw, tv_gnss_vel;      // GNSS数据显示控件
    TextView tv_nmea_tim, tv_nmea_lat, tv_nmea_lng, tv_nmea_alt, tv_nmea_her, tv_nmea_yaw, tv_nmea_vel;     // NMEA数据显示控件
    Button   btn_save;      // 数据保存按钮
    private float[] wib = new float[3], fsf = new float[3], mag = new float[3];     // 运动传感器数据
    private float pre;      // 气压传感器数据
    private int[] CNT = new int[]{0, 0, 0, 0};      // 计数值
    private float[] sensordata = new float[10];     // 运动传感器数据数组
    private double[] gnssdata = new double[8];      // GNSS数据数组
    private double[] nmeadata = new double[10];     // NMEA数据数组
    public static long t_stp, t0_stp;               // 系统时间标志
    public static float t;                          // 系统时间
    public static float PI = 3.141592653f;          // PI常值
    public static float DEG = PI / 180.0f;          // degree转换常值

    private static final int DISP_SENSORS = 201;    // 传感器数据显示消息标签
    private static final int DISP_GNSS = 202;       // GNSS数据显示标签
    private static final int DISP_NMEA = 203;       // NMEA数据显示标签
    private static final int OPEN_SET_REQUEST_CODE = 600;   // 权限请求标志
    private PSINSDataStore dataStore;               // 数据存储类
    private static boolean isSave = false;          // 数据保存标志

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        tv_time = findViewById(R.id.tv_time);       // 控件初始化
        tv_wx = findViewById(R.id.tv_Gyrox);
        tv_wy = findViewById(R.id.tv_Gyroy);
        tv_wz = findViewById(R.id.tv_Gyroz);
        tv_fx = findViewById(R.id.tv_Accex);
        tv_fy = findViewById(R.id.tv_Accey);
        tv_fz = findViewById(R.id.tv_Accez);
        tv_mx = findViewById(R.id.tv_Magnx);
        tv_my = findViewById(R.id.tv_Magny);
        tv_mz = findViewById(R.id.tv_Magnz);
        tv_pr = findViewById(R.id.tv_Pre);
        tv_gnss_tim = findViewById(R.id.tv_GNSStime);
        tv_gnss_lat = findViewById(R.id.tv_GNSSLat);
        tv_gnss_lng = findViewById(R.id.tv_GNSSLng);
        tv_gnss_alt = findViewById(R.id.tv_GNSSAlt);
        tv_gnss_yaw = findViewById(R.id.tv_GNSSYaw);
        tv_gnss_vel = findViewById(R.id.tv_GNSSVel);
        tv_nmea_tim = findViewById(R.id.tv_NMEAtime);
        tv_nmea_lat = findViewById(R.id.tv_NMEALat);
        tv_nmea_lng = findViewById(R.id.tv_NMEALng);
        tv_nmea_alt = findViewById(R.id.tv_NMEAAlt);
        tv_nmea_her = findViewById(R.id.tv_NMEAHerr);
        tv_nmea_yaw = findViewById(R.id.tv_NMEAYaw);
        tv_nmea_vel = findViewById(R.id.tv_NMEAVel);
        btn_save = findViewById(R.id.btn_save);

        // 请求权限
        int hasPermission = ContextCompat.checkSelfPermission(getApplication(),
                Manifest.permission.ACCESS_FINE_LOCATION);
        if (hasPermission != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                    OPEN_SET_REQUEST_CODE);
        }

        t0_stp = System.currentTimeMillis();
        MsgHandler msgHandler = new MsgHandler();       // 消息处理handler
        dataStore = new PSINSDataStore(getApplicationContext());    // 数据保存类
        SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);     // 定义SensorManager
        Sensor sensor_gyro = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);    // 定义sensors
        Sensor sensor_acce = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER_UNCALIBRATED);
        Sensor sensor_magn = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED);
        Sensor sensor_pres = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
        sensorManager.registerListener(new SensorEventListener() {      // 注册陀螺仪数据监听
            @Override
            public void onSensorChanged(SensorEvent event) {
                wib[0] += event.values[0];
                wib[1] += event.values[1];
                wib[2] += event.values[2];
                CNT[0]++;
            }

            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
            }
        }, sensor_gyro, sensorManager.SENSOR_DELAY_FASTEST);
        sensorManager.registerListener(new SensorEventListener() {      // 注册加速度计数据监听
            @Override
            public void onSensorChanged(SensorEvent event) {
                fsf[0] += event.values[0];
                fsf[1] += event.values[1];
                fsf[2] += event.values[2];
                CNT[1]++;
            }
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
            }
        }, sensor_acce, sensorManager.SENSOR_DELAY_FASTEST);
        sensorManager.registerListener(new SensorEventListener() {      // 注册磁强计数据监听
            @Override
            public void onSensorChanged(SensorEvent event) {
                mag[0] += event.values[0];
                mag[1] += event.values[1];
                mag[2] += event.values[2];
                CNT[2]++;
            }
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
            }
        }, sensor_magn, sensorManager.SENSOR_DELAY_FASTEST);
        sensorManager.registerListener(new SensorEventListener() {      // 注册气压数据监听
            @Override
            public void onSensorChanged(SensorEvent event) {
                pre += event.values[0];
                CNT[3]++;
            }
            @Override
            public void onAccuracyChanged(Sensor sensor, int accuracy) {
            }
        }, sensor_pres, sensorManager.SENSOR_DELAY_FASTEST);

        Timer timer = new Timer();              // 定时器——用于定时采样保存数据
        timer.schedule(new TimerTask() {        // 定义定时任务
            @Override
            public void run() {
                t_stp = System.currentTimeMillis();
                t_stp = t_stp - t0_stp;         // 计算系统时间
                t = t_stp / 1000.0f;
                if (CNT[0] != 0 && CNT[1] != 0 && CNT[2] != 0 && CNT[3] != 0) {     // 当所有传感器有数时记录数据输出
                    for (int i = 0; i < 3; i++) {
                        sensordata[i] = wib[i] / CNT[0] / DEG;
                        wib[i] = 0;
                        sensordata[i+3] = fsf[i] / CNT[1];
                        fsf[i] = 0;
                        sensordata[i+6] = mag[i] / CNT[2];
                        mag[i] = 0;
                    }
                    sensordata[9] = pre / CNT[3];
                    pre = 0;
                    CNT[0] = 0;
                    CNT[1] = 0;
                    CNT[2] = 0;
                    CNT[3] = 0;
                }
                // 发送消息
                if (isSave && dataStore!=null)
                    dataStore.writebindata(sensordata, gnssdata, nmeadata, t);  //保存全部数据
                Message msg = msgHandler.obtainMessage();       // 发送消息更新传感器数据
                msg.arg1 = DISP_SENSORS;
                msgHandler.sendMessage(msg);
            }
        }, 0, 10);      // 10ms任务

        LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
        locationManager.addNmeaListener(new OnNmeaMessageListener() {
            @Override
            public void onNmeaMessage(String message, long timestamp) {
                String head = message.substring(0,6);
                if (head.equals("$GPVTG") || head.equals("$GNVTG")) {       // 速度数据
                    String[] contents = message.split(",");          // 切分字符串
                    if (contents[7].length()>0) {                           // 判断是否为有效信息
                        double yaw = 0.0;
                        if (contents[1].length()>0) {
                            yaw = Double.parseDouble(contents[1]);          // 航迹角
                        }
                        nmeadata[8] = yaw;
                        nmeadata[9] = Double.parseDouble(contents[7])/3.6;  // 水平速度（km/h转成m/s）
                    }
                } else if (head.equals("$GPGGA") || head.equals("$GNGGA")) {
                    String[] contents = message.split(",");
                    if (contents[1].length()>0) {
                        nmeadata[0] = Double.parseDouble(contents[1]);      // UTC
                        nmeadata[1] = Double.parseDouble(contents[2]);      // Lat
                        nmeadata[2] = Double.parseDouble(contents[4]);      // Lng
                        nmeadata[3] = Double.parseDouble(contents[6]);      // State
                        nmeadata[4] = Double.parseDouble(contents[7]);      // nS
                        nmeadata[5] = Double.parseDouble(contents[8]);      // DOP
                        nmeadata[6] = Double.parseDouble(contents[9]);      // ALt
                        nmeadata[7] = Double.parseDouble(contents[11]);     // Herr
                        Message msg = msgHandler.obtainMessage();           // 发送消息更新显示
                        msg.arg1 = DISP_NMEA;
                        msgHandler.sendMessage(msg);
                    }
                }
            }
        });

        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, new LocationListener() {
            @Override
            public void onLocationChanged(@NonNull Location location) {     // 位置变化回调方法
                gnssdata[0] = location.getTime();                           // UTC时间
                gnssdata[1] = location.getLatitude();                       // 纬度
                gnssdata[2] = location.getLongitude();                      // 经度
                gnssdata[3] = location.getAltitude();                       // 高度
                gnssdata[4] = location.getAccuracy();                       // 水平定位精度
                gnssdata[5] = location.getBearing();                        // 航迹角
                gnssdata[6] = location.getSpeed();                          // 水平速度
                gnssdata[7] = location.getSpeedAccuracyMetersPerSecond();   // 速度精度
                Message msg = msgHandler.obtainMessage();                   // 发送消息更新数据
                msg.arg1 = DISP_GNSS;
                msgHandler.sendMessage(msg);
            }
        });

        btn_save.setOnClickListener(new View.OnClickListener() {            // 保存按钮监听函数
            @Override
            public void onClick(View v) {
                if (isSave) {
                    isSave = false;
                    dataStore.close();
                    btn_save.setText("SAVE");
                } else {
                    dataStore.open();
                    isSave = true;
                    btn_save.setText("STOP");
                }
            }
        });
    }

    private class MsgHandler extends Handler {          // 消息处理Handler
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.arg1) {
                case DISP_SENSORS:
                    SensorDataDisp(sensordata, t);
                    break;
                case DISP_GNSS:
                    GNSSDataDisp(gnssdata);
                    break;
                case DISP_NMEA:
                    NMEADataDisp(nmeadata);
                    break;
            }
        }
    }

    private void SensorDataDisp(float[]sensorData, float t)
    {
        tv_time.setText(String.format("%8.3f",t));
        tv_wx.setText(String.format("%8.4f",sensorData[0]));
        tv_wy.setText(String.format("%8.4f",sensorData[1]));
        tv_wz.setText(String.format("%8.4f",sensorData[2]));
        tv_fx.setText(String.format("%8.4f",sensorData[3]));
        tv_fy.setText(String.format("%8.4f",sensorData[4]));
        tv_fz.setText(String.format("%8.4f",sensorData[5]));
        tv_mx.setText(String.format("%8.4f",sensorData[6]));
        tv_my.setText(String.format("%8.4f",sensorData[7]));
        tv_mz.setText(String.format("%8.4f",sensorData[8]));
        tv_pr.setText(String.format("%8.4f",sensorData[9]));
    }

    private void GNSSDataDisp(double[] gnssData)
    {
        tv_gnss_tim.setText(UTCtoCST((long) gnssData[0]));
        tv_gnss_lat.setText(String.valueOf(gnssData[1]));
        tv_gnss_lng.setText(String.valueOf(gnssData[2]));
        tv_gnss_alt.setText(String.valueOf(gnssData[3]));
        tv_gnss_yaw.setText(String.valueOf(gnssData[5]));
        tv_gnss_vel.setText(String.valueOf(gnssData[6]));
    }

    private void NMEADataDisp(double[] nmeaData)
    {
        tv_nmea_tim.setText(String.valueOf(nmeaData[0]));
        tv_nmea_lat.setText(String.valueOf(nmeaData[1]));
        tv_nmea_lng.setText(String.valueOf(nmeaData[2]));
        tv_nmea_alt.setText(String.valueOf(nmeaData[6]));
        tv_nmea_her.setText(String.valueOf(nmeaData[7]));
        tv_nmea_yaw.setText(String.valueOf(nmeaData[8]));
        tv_nmea_vel.setText(String.valueOf(nmeaData[9]));
    }

    public static String UTCtoCST(long sec) {
        SimpleDateFormat format = new SimpleDateFormat("HHmmss"); //格式按需自定义
        format.setTimeZone(TimeZone.getTimeZone( "GMT+00")); //北京时区GMT+8
        return format.format(new Date(sec));
    }
}